using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.Contracts;
using Konst3d.Efficiency.Suite;
using System.Collections.Specialized;

namespace Konst3d.Efficiency.Suite.SparsedBinary
{
    internal class CountDownTimerStorage: ICountDownTimerCollection, ICountDownTimerStorage, IDisposable
    {
        #region Constants

        private const string COUNTERS_FILE_EXT = ".counters";

        #endregion // Constants

        #region Create/Load/Delete Methods

        public static CountDownTimerStorage Create(string fileName, bool overwrite, ICryptographicEngine cryptographicEngine) // file name w/o ext
        {
            Contract.Requires(!String.IsNullOrEmpty(fileName));

            CountDownTimersFile file = null;
            LabelsStorage labels = null;

            try
            {
                file = CountDownTimersFile.Create(fileName + COUNTERS_FILE_EXT, overwrite);
                labels = LabelsStorage.Create(fileName, overwrite, cryptographicEngine);

                return new CountDownTimerStorage(file, labels);
            }
            catch
            {
                if (file != null)
                {
                    file.Dispose();
                }

                if (labels != null)
                {
                    labels.Dispose();
                }

                throw;
            }
        }

        public static CountDownTimerStorage Open(string fileName, ICryptographicEngine cryptographicEngine)
        {
            Contract.Requires(!String.IsNullOrEmpty(fileName));

            CountDownTimersFile file = null;
            LabelsStorage labels = null;

            try
            {
                file = CountDownTimersFile.Open(fileName + COUNTERS_FILE_EXT);
                labels = LabelsStorage.Open(fileName, cryptographicEngine);

                return new CountDownTimerStorage(file, labels);
            }
            catch
            {
                if (file != null)
                {
                    file.Dispose();
                }

                if (labels != null)
                {
                    labels.Dispose();
                }

                throw;
            }
        }

        public void Delete()
        {
            Contract.Assert(!_disposed);

            _file.Delete();
            _labels.Delete();

            Dispose();
        }

        #endregion // Create/Load/Delete Methods

        #region Constructor/Finalizer

        private CountDownTimerStorage(CountDownTimersFile file, LabelsStorage labels)
        {
            Contract.Requires(file != null);
            Contract.Requires(labels != null);

            _file = file;
            _labels = labels;

            var entries = _file.GetAll();

            foreach(var entry in entries)
            {
                _timers.Add(entry.Key,
                            new CountDownTimer(this, entry.Key,
                                                _labels.GetLabel(entry.Value.TitleID),
                                                _labels.GetLabel(entry.Value.DescriptionID),
                                                entry.Value.TargetDate.GetDateTime(),
                                                entry.Value.CreatedDate.GetDateTime()));
            }
        }

        ~CountDownTimerStorage()
        {
            Dispose(false);
        }

        #endregion // Constructor/Finalizer

        #region ICountDownTimerCollection Members

		public int Count
		{
			get
			{
				return _timers.Count;
			}
		}

        public ICountDownTimer this[int id]
        {
            get
            {
                return _timers[id];
            }
        }

        public int Add(string title, string description, DateTime target, DateTime created)
        {
            int id = _file.AddEntry(_labels.AddLabel(title), _labels.AddLabel(description), target, created);
            _timers.Add(id, new CountDownTimer(this, id, title, description, target, created));

            if (CollectionChanged != null)
            {
                var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); // TOFIX: optimize
                CollectionChanged(this, args);
            }

            return id;
        }

        public void Remove(int id)
        {
            Contract.Assert(_timers.ContainsKey(id));

            _labels.DeleteLabel(_file.GetEntryTitleID(id));
            _labels.DeleteLabel(_file.GetEntryDescrID(id));

            _file.RemoveEntry(id);
            _timers.Remove(id);

            if (CollectionChanged != null)
            {
                var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); // TOFIX: optimize
                CollectionChanged(this, args);
            }
        }

        #endregion

        #region INotifyCollectionChanged Members

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        #endregion

        #region IEnumerable<ICountDownTimer> Members

        public IEnumerator<ICountDownTimer> GetEnumerator()
        {
            return _timers.Values.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _timers.Values.GetEnumerator();
        }

        #endregion

        #region ICountDownTimerStorage Members

        void ICountDownTimerStorage.UpdateTitle(int id, string title)
        {
            Contract.Requires(id >= 0);

            int labelID = _file.GetEntryTitleID(id);
            int newLabelID = _labels.UpdateLabel(labelID, title);

            _file.SetEntryTitleID(id, newLabelID);

            if (CollectionChanged != null)
            {
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); // TOFIX: optimize
            }
        }

        void ICountDownTimerStorage.UpdateDescription(int id, string description)
        {
            Contract.Requires(id >= 0);

            int labelID = _file.GetEntryDescrID(id);
            int newLabelID = _labels.UpdateLabel(labelID, description);

            _file.SetEntryDescrID(id, newLabelID);

            if (CollectionChanged != null)
            {
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); // TOFIX: optimize
            }
        }

        void ICountDownTimerStorage.UpdateTargetDate(int id, DateTime targetDate)
        {
            Contract.Requires(id >= 0);

            _file.SetEntryTargetDate(id, targetDate);

            if (CollectionChanged != null)
            {
                CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); // TOFIX: optimize
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            Dispose(true);
        }

        private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _file.Dispose();
                    _file = null;

                    _labels.Dispose();
                    _labels = null;

                    _timers.Clear();
                    _timers = null;
                }

                _disposed = true;
            }
        }

        #endregion

        #region Fields

        private bool _disposed = false;
        private CountDownTimersFile _file;
        private LabelsStorage _labels;
        private Dictionary<int, CountDownTimer> _timers = new Dictionary<int, CountDownTimer>();

        #endregion // Fields
    }
}
